package provider

import (
	. "cppcloud"
	"fmt"
	"tool"
)

var prvdidCount = 0

// ProviderBase 分布式服务提供者父类
type ProviderBase struct {
	regname        string
	host           string
	port           int // 不提供时会选择一些随机端口
	url            string
	scheme         string // 和protocol，任选一个指定协议
	protocol       int    // 1 tcp, 2 udp, 3 http, 4 https
	weight         int    // default = 100
	idc            int
	rack           int
	enable         int // default = 1
	desc           string
	prvdid         int
	async_response bool
	httpPath       string
	cloudapp       *CloudApp
}

func CreateProviderBase(app *CloudApp) *ProviderBase {
	return &ProviderBase{weight: 100, enable: 1, cloudapp: app}
}

func (pbase *ProviderBase) SetRegName(regname string) {
	pbase.regname = regname
}

func (pbase *ProviderBase) SetHost(host string) {
	pbase.host = host
}

func (pbase *ProviderBase) SetPort(port int) {
	pbase.port = port
}

func (pbase *ProviderBase) SetUrl(url string) {
	pbase.url = url
}

func (pbase *ProviderBase) SetScheme(scheme string) {
	pbase.scheme = scheme
}

func (pbase *ProviderBase) SetProtocol(protocol int) {
	pbase.protocol = protocol
}

func (pbase *ProviderBase) SetWeight(weight int) {
	pbase.weight = weight
}

func (pbase *ProviderBase) SetEnable(enable int) {
	pbase.enable = enable
}

func (pbase *ProviderBase) SetDesc(desc string) {
	pbase.desc = desc
}

func (pbase *ProviderBase) SetPrvdid(prvdid int) {
	pbase.prvdid = prvdid
}

func (pbase *ProviderBase) SetIdc(idc int) {
	pbase.idc = idc
}

func (pbase *ProviderBase) SetRack(rack int) {
	pbase.rack = rack
}

func (pbase *ProviderBase) SetHttpPath(httpPath string) {
	pbase.httpPath = httpPath
}

func (pbase *ProviderBase) getPrvdKey() string {
	return fmt.Sprintf("%s-%d-%d",
		pbase.regname, pbase.cloudapp.Svrid(), pbase.prvdid)
}

// 反馈当次调用成功还是失败
func (pbase *ProviderBase) TellResult(isOk bool) {
	pbase.cloudapp.SvrStatInstance().AddPrvdCount(pbase.getPrvdKey(), isOk, 1)
}

func (pbase *ProviderBase) Regist(reg bool) {
	if "" == pbase.regname {
		pbase.regname = pbase.cloudapp.SvrName()
	}

	pbase.prvdid = prvdidCount
	prvdidCount++

	if 0 == pbase.port { // 随机端口
		pbase.port = 3000 + pbase.prvdid
	}

	pbase.buildURL()
	pbase.cloudapp.AddNotifyCallBack("reconnect_ok", pbase.onServReconnect)
	pbase.cloudapp.AddNotifyCallBack("provider", pbase.onSetProvider)

	if reg {
		pbase.regProvider()
	}
}

func (pbase *ProviderBase) buildURL() {
	if 0 == pbase.protocol {
		schemeProtocol := map[string]int{
			"tcp": 1, "udp": 2, "http": 3, "https": 4, "": 0,
		}
		pbase.protocol = schemeProtocol[pbase.scheme]
	}

	if "" != pbase.url {
		return
	}

	if "" == pbase.host {
		pbase.host = pbase.cloudapp.CliIP()
	}

	urlprefix := []string{"unknow", "tcp", "udp", "http", "https"}
	pbase.url = urlprefix[pbase.protocol] + "://" + pbase.host + ":" + fmt.Sprint(pbase.port) + pbase.httpPath
}

func (pbase *ProviderBase) regProvider(prop ...string) {

	paramReq0 := make(map[string]interface{})
	paramReq := make(map[string]interface{})
	paramReq0["regname"] = pbase.regname

	if len(prop) == 0 {
		prop = []string{"prvdid", "url", "desc", "protocol", "weight", "enable", "idc", "rack"}
	}

	for _, propName := range prop {
		switch propName {
		case "prvdid":
			paramReq[propName] = pbase.prvdid
		case "url":
			paramReq[propName] = pbase.url
		case "desc":
			paramReq[propName] = pbase.desc
		case "protocol":
			paramReq[propName] = pbase.protocol
		case "weight":
			paramReq[propName] = pbase.weight
		case "enable":
			paramReq[propName] = pbase.enable
		case "idc":
			paramReq[propName] = pbase.idc
		case "rack":
			paramReq[propName] = pbase.rack
		}
	}

	paramReq0["svrprop"] = paramReq
	pbase.cloudapp.RequestNoWait(CMD_SVRREGISTER_REQ, paramReq0)
	//fmt.Println("REGTCPPRVD| regname="+pbase.regname, ret, err)
}

// 客户端重连回调
func (pbase *ProviderBase) onServReconnect(msg map[string]interface{}) (code int, result interface{}) {
	fmt.Println("Found serv reconnect ok")
	pbase.regProvider()
	return 0, nil
}

// web上修改provider时回调
func (pbase *ProviderBase) onSetProvider(msg map[string]interface{}) (code int, result interface{}) {
	regname, ok1 := tool.JSONGetString("regname")
	prvdid, ok2 := tool.JSONGetInt("prvdid")
	if ok1 && ok2 && regname == pbase.regname && prvdid == pbase.prvdid {
		if enable, ok3 := tool.JSONGetInt("enable"); ok3 {
			pbase.SetEnable(enable)
		}
		if weight, ok4 := tool.JSONGetInt("weight"); ok4 {
			pbase.SetWeight(weight)
		}

		pbase.regProvider("weight", "enable")
	}

	return 0, nil
}

/* 反射获取field值时需要大写字母开头的变量才可以
func (pbase *ProviderBase) GetFieldByName(name string) interface{} {
	fieldValue := reflect.ValueOf(*pbase).FieldByName(name)
	return fieldValue.Interface()
}
*/
